#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <unistd.h>
#include <string.h>

// 字节数组也可以保存0X00-0XFF，也可以摆脱'\0'(0)结束的字符串．但需要知道数组长度。
// 内存操作也需要包含C标准库<string.h>
// 几个常见的字符串操作。
// *** memset 将所有字节配置为某个字节数据。
// *** memcmp 比较。
// 处理重叠内存区域：memcpy不能处理重叠内存区域，而memmove可以。
// 性能：在大多数情况下，由于memmove需要处理重叠情况，它可能会比memcpy稍慢。然而，在没有重叠时，许多实现可能会使memmove退化为memcpy以优化性能。
// *** memcpy 拷贝。
// memmove 可重叠拷贝。
// memchr 查找一个字符
// 操作出界可能会崩溃。

// 　将内存内容打印出来．
void printMemData(const char *memexp, const char *memptr, int memlen)
{
    printf("%s", memexp); // 　打印内存说明．
    for (int i = 0; i < memlen; i++)
    {
        printf("0x%02x ", (uint8_t)memptr[i]); // 　这里强制转换为uint8_t类型，否则负数的时候，会打印int型的如：0xffffffff
        if (i % 16 == 15)
        {
            printf("\n"); // 每16字节，换行．
        }
    }
    printf("\n");
}

void check_memset()
{
    char tmpbuf[32];
    memset(tmpbuf, 0x5a, sizeof(tmpbuf));
    printMemData("memset check buf:", tmpbuf, sizeof(tmpbuf));
}

void check_memcmp()
{
    // 　memcmp就是：tmpbuf1[i] - tmpbuf2[i], 等于0，继续下一个比较，!=0(<0退出，>0退出)．
    // 　比较长度都不能超过任意字节数组(tmpbuf1或tmpbuf2)的长度．虽然只是读取，只读内存访问超界也可能崩溃．
    char tmpbuf1[8];
    char tmpbuf2[8];
    memset(tmpbuf1, 1, sizeof(tmpbuf1));
    memset(tmpbuf2, 3, sizeof(tmpbuf2));
    // -2, tmpbuf1　< tmpbuf2.
    printf("memcmp, 1, 2, res = %d\n", memcmp(tmpbuf1, tmpbuf2, sizeof(tmpbuf2)));
    memset(tmpbuf1, 5, sizeof(tmpbuf1));
    memset(tmpbuf2, 1, sizeof(tmpbuf2));
    // 4, tmpbuf1　> tmpbuf2
    printf("memcmp, 2, 1, res = %d\n", memcmp(tmpbuf1, tmpbuf2, sizeof(tmpbuf2)));
    for (int i = 0; i < (int)sizeof(tmpbuf1); i++)
    {
        tmpbuf1[i] = i;
        tmpbuf2[i] = i;
    }
    // =0, tmpbuf1　== tmpbuf2
    printf("memcmp same buf, res = %d\n", memcmp(tmpbuf1, tmpbuf2, sizeof(tmpbuf2)));
}

void check_memcpy()
{
    char tmpbuf1[8];
    char tmpbuf2[8];
    for (int i = 0; i < (int)sizeof(tmpbuf1); i++)
    {
        tmpbuf1[i] = sizeof(tmpbuf1) - i;
    }
    memcpy(tmpbuf2, tmpbuf1, sizeof(tmpbuf1));
    printMemData("memcpy tmpbuf2 buf:", tmpbuf2, sizeof(tmpbuf2));
}

void check_memmove()
{
    char tmpbuf1[16];
    for (int i = 0; i < (int)sizeof(tmpbuf1); i++)
    {
        tmpbuf1[i] = i;
    }
    memcpy(tmpbuf1 + 4, tmpbuf1, 8); // 　有警告提醒我们，拷贝空间有重复．但是我在PC端拷贝居然没有被覆盖．可能内部做了优化．
    printMemData("memmove-memcpy buf :", tmpbuf1, sizeof(tmpbuf1));
    for (int i = 0; i < (int)sizeof(tmpbuf1); i++)
    {
        tmpbuf1[i] = i;
    }
    memmove(tmpbuf1 + 4, tmpbuf1, 8); // 没有警告
    printMemData("memmove-memmove buf:", tmpbuf1, sizeof(tmpbuf1));
}

void check_memchr()
{
    char tmpbuf1[16];
    for (int i = 0; i < (int)sizeof(tmpbuf1); i++)
    {
        tmpbuf1[i] = i;
    }
    char *tmpptr = memchr(tmpbuf1, 0x0e, sizeof(tmpbuf1));
    if (tmpptr)
    {
        printf("chk1, memchr find point=%d\n", (int)(tmpptr - tmpbuf1));
    }
    else
    {
        printf("chk1, memchr not find\n");
    }
    tmpptr = memchr(tmpbuf1, 0xfe, sizeof(tmpbuf1));
    if (tmpptr)
    {
        printf("chk2, memchr find point=%d\n", (int)(tmpptr - tmpbuf1));
    }
    else
    {
        printf("chk2, memchr not find\n");
    }
}

int main(int argc, char **argv)
{
    check_memset();
    check_memcmp();
    check_memcpy();
    check_memmove();
    check_memchr();
    return 1;
}
